﻿using MyNes.Core;
using System;
using System.Collections.Generic;
using System.Text;

namespace BITUI.nes
{
    static class SimTool
    {
        public static byte[] pixel;
        public static int[] palette;



        class NesAudioMixer : BITUI.Audio.AudioSystem.IMixer
        {
            static ushort buffersize = 1024 * 5;
            static float[] audiobuf = new float[buffersize];
            static int audiowritepos = 0;
            static int audioreadpos = 0;
            static int samples_added = 0;

            public float[] GetAudioData(int floatcount)
            {
                var buflen = audiobuf.Length;
                float[] data = new float[floatcount];
                for (var i = 0; i < floatcount / 2; i++)
                {
                    var sample = audiobuf[audioreadpos++ % buflen];
                    samples_added--;
                    data[i * 2] = sample;
                    data[i * 2 + 1] = sample;
                }

                return data;
            }

            public bool GetAudioData(int floatcount, out IntPtr outdata, out int outfloatcount)
            {
                unsafe
                {
                    var buflen = audiobuf.Length;
                    fixed (float* audiodata = audiobuf)
                    {
                        outdata = (IntPtr)(audiodata + (audioreadpos % buflen));

                        var maxfloatcount = buflen - (audioreadpos % buflen);

                        outfloatcount = floatcount;
                        if (floatcount > maxfloatcount)
                            outfloatcount = maxfloatcount;
                        audioreadpos += outfloatcount;
                        return true;
                    }
                }

            }

            public unsafe bool Mix(float* data, int len, int freq, int channel)
            {
                //if (samples_added < 2048)
                //    return true;

                //var buflen = audiobuf.Length;
                //for (var i = 0; i < len / 2; i++)
                //{
                //    if (samples_added > 0)
                //    {

                //    }
                //}

                return true;
            }

            public unsafe void MixFloat_44100_2(float* stream, int streamlen)
            {
                if (samples_added < 2048)
                {
                    return;
                }

                var len1 = streamlen;
                var maxcount = audiobuf.Length - audioreadpos;
                if (len1 > maxcount)
                    len1 = maxcount;

                //因为使用的循环缓冲区，一次可能弄不完
                BITUI.Audio.AudioSystem.MixFloatAudio(stream, 0, streamlen, audiobuf, audioreadpos, len1);
                audioreadpos += len1;
                if (audioreadpos >= audiobuf.Length)
                    audioreadpos -= audiobuf.Length;

                if (len1 < streamlen)//循环了，再来一次
                {
                    var len2 = streamlen - len1;
                    maxcount = audiobuf.Length - audioreadpos;
                    if (len2 > maxcount)
                    {
                        //再次触发循环，这应该是不可能的，循环缓冲区的容量比混音缓冲大得多
                        len2 = maxcount;
                    }
                    BITUI.Audio.AudioSystem.MixFloatAudio(stream, len1, streamlen, audiobuf, audioreadpos, len2);
                    audioreadpos += len2;
                    if (audioreadpos >= audiobuf.Length)
                        audioreadpos -= audiobuf.Length;
                }

            }

            public void OnNesAudioData(sbyte[] buffer, int samples_count)
            {
                var buflen = audiobuf.Length;
                for (var i = 0; i < samples_count; i++)
                {
                    float sample = (buffer[i] / 128.0f); //从8bit音源 -127 ~127 ，转换为float音源（ -1.0~1.0）；

                    audiobuf[audiowritepos++ % buflen] = sample;
                    audiobuf[audiowritepos++ % buflen] = sample;
                    if (samples_added < 2048) //只是作为计数开始缓存
                        samples_added++;
                }

                if (audiowritepos >= buflen)
                    audiowritepos -= buflen;
            }

        }
        public static void Init()
        {

            MyNesMain.Light_Init();

            if (BITUI.AppFramework.AudioSystem.AudioInited)
            {
                var mixer = new NesAudioMixer();
                BITUI.AppFramework.AudioSystem.AddMixer("nesaudio", mixer);
                MyNesMain.RendererSettings.Audio_Frequency = 44100;
                MyNes.Core.NesEmu.Light_SetupAudioSamples(mixer.OnNesAudioData);
            }

            NesEmu.Light_SetupVideoRender((pixel, palette) =>
            {
                SimTool.pixel = pixel;
                SimTool.palette = palette;
            });
            loadedNesFile = null;
            conP0 = new Controller();
        }

        public static string loadedNesFile
        {
            get;
            private set;
        }
        public static Controller conP0
        {
            get;
            private set;
        }
        public static bool LoadAndStartGame(string nesfilename)
        {
            if (loadedNesFile != null)
            {
                throw new Exception("have a game,close first.");
            }
            loadedNesFile = nesfilename;
            MyNes.Core.NesEmu.LoadGame(nesfilename, out bool success, true);
            MyNes.Core.NesEmu.SetupControllersP1(conP0);

            return success;
        }
        static void Close()
        {
            if (loadedNesFile != null)
            {
                try
                {
                    MyNes.Core.MyNesMain.Shutdown();
                }
                catch
                {

                }
            }
            loadedNesFile = null;
        }
    }
}
